﻿#region Copyright (c) 2010-2011 SFJoy .All rights reserved
//******************************************************   
//* Copyright (c) 2010-2011 SFJoy .All rights reserved
//* FileName:		HtmlContext.cs
//* CLR version: 2.0.50727.3615
//* Author: 			SFJoy
//* Version:		 	1.0.0
//* Date:        2010-12-7 10:16:34"
//* Description:	
//*
//* History:			
//*******************************************************
#endregion Copyright (c) 2010-2011 Yeepay .All rights reserved
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Globalization;

namespace UtilityLibrary.Http
{
    public class HtmlContext
    {
        /// <summary>
        /// 临时转换字符串
        /// </summary>
        private const string c_TempString = "~!@#$%^&*()_+_)(*&^%$#@!~";
        /// <summary>
        /// 默认匹配name--value对的正则表达式
        /// </summary>
        private const string c_DefaultNameRegex = @"[nN][aA][mM][eE]=(""{0}""|'{0}'|{0})\s+.*?[vV][aA][lL][uU][eE]=(""(.*?)""|'(.*?)'|(.*?))[\s>/]+";
        private const string c_DefaultNameRegex2 = @"[vV][aA][lL][uU][eE]=(""(.*?)""|'(.*?)'|(.*?))\s.*?[nN][aA][mM][eE]=(""{0}""|'{0}'|{0}).*?>";
        /// <summary>
        /// 默认匹配id--value对的正则表达式
        /// </summary>
        private const string c_DefaultIdRegex = @"[iI][dD]=(""{0}""|'{0}'|{0})\s+.*?[vV][aA][lL][uU][eE]=(""(.*?)""|'(.*?)'|(.*?))[\s>/]+";
        private const string c_DefaultIdRegex2 = @"[vV][aA][lL][uU][eE]=(""(.*?)""|'(.*?)'|(.*?))\s.*?[iI][dD]=(""{0}""|'{0}'|{0}).*?>";
        /// <summary>
        /// 匹配Form表单的正则表达式
        /// </summary>
        private const string c_FromRegex1 = @"(<form[^>]*?[nN][aA][mM][eE]=""{0}""[^>]*?>[\s\S]*?</form>)";
        private const string c_FromRegex2 = @"(<form[^>]*?[nN][aA][mM][eE]={0}[^>]*?>[\s\S]*?</form>)";
        private const string c_FromRegex3 = @"(<form[^>]*?[nN][aA][mM][eE]='{0}'[^>]*?>[\s\S]*?</form>)";

        /// <summary>
        /// 获取正则表达式的第一个匹配结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="html">匹配字符串</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public static String MatchRegexValue(String strRegex, String html)
        {
            String returnValue = String.Empty;

            //匹配正则,忽略大小写
            Regex regex = new Regex(strRegex, RegexOptions.IgnoreCase);
            Match match = regex.Match(html);

            //匹配成功则将匹配值赋给返回值
            if (match.Success) returnValue = match.Value;
            return returnValue;
        }

        /// <summary>
        /// 获取正则表达式的结果集
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="html">匹配字符串</param>
        /// <returns>结果集</returns>
        public static String[] MatchRegexValues(String strRegex, String html)
        {
            //匹配正则,忽略大小写
            Regex regex = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection mc = regex.Matches(html);

            //根据匹配结果集大小创建返回字符串集
            String[] returnValue = new String[mc.Count];

            //循环匹配结果集将匹配值赋给返回结果集的对应值
            for (int i = 0; i < mc.Count; i++)
            {
                returnValue[i] = mc[i].Value;
            }

            return returnValue;
        }

        /// <summary>
        /// 提取正则表达式的第N个匹配组结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="html">匹配字符串</param>
        /// <param name="index">捕获组索引</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public static String MatchRegexResult(String strRegex, String html, Int32 index)
        {
            String returnValue = String.Empty;

            //匹配正则，匹配前将匹配组标记$符号暂时转换为临时字符串
            Regex regex = new Regex(strRegex, RegexOptions.IgnoreCase);
            Match match = regex.Match(html.Replace("$", c_TempString));

            //根据捕获组索引，获取匹配结果
            if (match.Success) returnValue = match.Result("$" + index.ToString("D", CultureInfo.CurrentCulture));

            //如果获得匹配结果值与匹配组索引标示相同，则作为匹配失败处理，将返回值设为空字符串
            if (returnValue == "$" + index.ToString("D", CultureInfo.CurrentCulture)) returnValue = String.Empty;

            //将临时字符串转换回匹配组标记$符号后，返回
            return returnValue.Replace(c_TempString, "$");
        }

        /// <summary>
        /// 提取正则表达式的第一个匹配组结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="value">匹配字符串</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public static String MatchRegexResult(String strRegex, String html)
        {
            return MatchRegexResult(strRegex, html, 1);
        }

        /// <summary>
        /// 提取正则表达式的第N个匹配组结果集
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="html">匹配字符串</param>
        /// <param name="index">捕获组索引</param>
        /// <returns>结果集</returns>
        public static String[] MatchRegexResults(String strRegex, String html, Int32 index)
        {
            //匹配正则，匹配前将匹配组标记$符号暂时转换为临时字符串
            Regex regex = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection mc = regex.Matches(html.Replace("$", c_TempString));

            //根据匹配结果集大小创建返回字符串集
            String[] returnValue = new String[mc.Count];

            //循环匹配结果集将匹配值赋给返回结果集的对应值
            for (int i = 0; i < mc.Count; i++)
            {
                //根据捕获组索引，获取匹配结果
                returnValue[i] = mc[i].Result("$" + index.ToString("D", CultureInfo.CurrentCulture));

                //如果获得匹配结果值与匹配组索引标示相同，则作为匹配失败处理，将返回值设为空字符串
                if (returnValue[i] == "$" + index.ToString("D", CultureInfo.CurrentCulture)) returnValue[i] = String.Empty;

                //将临时字符串转换回匹配组标记$符号后，赋值给返回值对应项
                returnValue[i] = returnValue[i].Replace(c_TempString, "$");
            }

            return returnValue;
        }

        /// <summary>
        /// 提取正则表达式的第一个匹配组结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="value">匹配字符串</param>
        /// <returns>结果集</returns>
        public static String[] MatchRegexResults(String strRegex, String html)
        {
            return MatchRegexResults(strRegex, html, 1);
        }

        /// <summary>
        /// Html正文
        /// </summary>
        public String Html { get; set; }

        /// <summary>
        /// 链接地址
        /// </summary>
        public Uri Url { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public HtmlContext()
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="html">Html正文</param>
        public HtmlContext(String html)
        {
            Html = html;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="html">Html正文</param>
        /// <param name="url">链接地址</param>
        public HtmlContext(String html, Uri url)
        {
            Html = html;
            Url = url;
        }

        /// <summary>
        /// 重载ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Html;
        }

        /// <summary>
        /// 提取正则表达式的第N个匹配组结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="index">捕获组索引</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public String Match(String strRegex, Int32 index)
        {
            return MatchRegexResult(strRegex, Html, index);
        }

        /// <summary>
        /// 提取正则表达式的第一个匹配组结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public String Match(String strRegex)
        {
            return MatchRegexResult(strRegex, Html);
        }

        /// <summary>
        /// 提取正则表达式的第N个匹配组结果集
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="index">捕获组索引</param>
        /// <returns>结果集</returns>
        public String[] Matchs(String strRegex, Int32 index)
        {
            return MatchRegexResults(strRegex, Html, index);
        }

        /// <summary>
        /// 提取正则表达式的第一个匹配组结果集
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <returns>结果集</returns>
        public String[] Matchs(String strRegex)
        {
            return MatchRegexResults(strRegex, Html);
        }

        /// <summary>
        /// 获取正则表达式的匹配结果
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <returns>结果(未匹配到返回String.Empty)</returns>
        public String Value(String strRegex)
        {
            return MatchRegexValue(strRegex, Html);
        }

        /// <summary>
        /// 获取正则表达式的匹配结果集
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <returns>结果集</returns>
        public String[] Values(String strRegex)
        {
            return MatchRegexValues(strRegex, Html);
        }

        /// <summary>
        /// 根据名称获得值
        /// </summary>
        /// <param name="name">名称</param>
        /// <returns>值</returns>
        public String ValueByName(String name)
        {
            String returnValue = String.Empty;

            //使用默认匹配name--value对的正则表达式，匹配Html属性，并将第三个匹配组的值赋给返回值
            int startIndex = 2;
            returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultNameRegex, name), Html, startIndex);
            if (!String.IsNullOrEmpty(returnValue))
            {
                for (int i = startIndex + 1; i < startIndex + 4; i++)
                {
                    returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultNameRegex, name), Html, i);
                    if (!String.IsNullOrEmpty(returnValue)) break;
                }
                return returnValue;

            }

            startIndex = 1;
            if (String.IsNullOrEmpty(returnValue))
            {
                returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultNameRegex2, name), Html, startIndex);
                if (!String.IsNullOrEmpty(returnValue))
                {
                    for (int i = startIndex + 1; i < startIndex + 4; i++)
                    {
                        returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultNameRegex2, name), Html, i);
                        if (!String.IsNullOrEmpty(returnValue)) break;
                    }
                    return returnValue;

                }
            }

            return returnValue;
        }

        /// <summary>
        /// 根据Id获得值
        /// </summary>
        /// <param name="name">名称</param>
        /// <returns>值</returns>
        public String ValueById(String id)
        {
            String returnValue = String.Empty;

            //使用默认匹配id--value对的正则表达式，匹配Html属性，并将第三个匹配组的值赋给返回值
            int startIndex = 2;
            returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultIdRegex, id), Html, startIndex);
            if (!String.IsNullOrEmpty(returnValue))
            {
                for (int i = startIndex + 1; i < startIndex + 4; i++)
                {
                    returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultIdRegex, id), Html, i);
                    if (!String.IsNullOrEmpty(returnValue)) break;
                }
                return returnValue;
            }

            startIndex = 1;
            if (String.IsNullOrEmpty(returnValue))
            {
                returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultIdRegex2, id), Html, startIndex);
                if (!String.IsNullOrEmpty(returnValue))
                {
                    for (int i = startIndex + 1; i < startIndex + 4; i++)
                    {
                        returnValue = MatchRegexResult(String.Format(CultureInfo.CurrentCulture, c_DefaultIdRegex2, id), Html, i);
                        if (!String.IsNullOrEmpty(returnValue)) break;
                    }
                }
                return returnValue;
            }

            return returnValue;
        }

        /// <summary>
        /// 根据表单名称从html正文中提取表单对象
        /// </summary>
        /// <param name="name">表单name属性</param>
        /// <returns>表单对象</returns>
        public HtmlFormContext From(String formName)
        {
            String formHtml = String.Empty;

            formHtml = Match(String.Format(CultureInfo.CurrentCulture, c_FromRegex1, formName));
            if (!String.IsNullOrEmpty(formHtml)) return new HtmlFormContext(formHtml, Url);

            formHtml = Match(String.Format(CultureInfo.CurrentCulture, c_FromRegex2, formName));
            if (!String.IsNullOrEmpty(formHtml)) return new HtmlFormContext(formHtml, Url);

            formHtml = Match(String.Format(CultureInfo.CurrentCulture, c_FromRegex3, formName));
            if (!String.IsNullOrEmpty(formHtml)) return new HtmlFormContext(formHtml, Url);

            return null;
        }

        /// <summary>
        /// 根据name组添加name-value对匹配的参数组
        /// </summary>
        /// <param name="vars"></param>
        public Dictionary<String, String> GetParamatersByName(params String[] vars)
        {
            Dictionary<String, String> returnValue = new Dictionary<String, String>();
            foreach (String name in vars)
            {
                returnValue.Add(name, ValueByName(name));
            }

            return returnValue;
        }

        /// <summary>
        /// 根据name组添加name-value对匹配的参数组
        /// </summary>
        /// <param name="vars"></param>
        public Dictionary<String, String> GetParamatersByName(Encoding encoding, params String[] vars)
        {
            Dictionary<String, String> returnValue = new Dictionary<String, String>();
            foreach (String name in vars)
            {
                returnValue.Add(name, HttpUtility.UrlEncode(ValueByName(name), encoding));
            }

            return returnValue;
        }

        /// <summary>
        /// 根据id组添加id-value对匹配的参数组
        /// </summary>
        /// <param name="vars"></param>
        public Dictionary<String, String> GetParamatersById(params String[] vars)
        {
            Dictionary<String, String> returnValue = new Dictionary<String, String>();
            foreach (String id in vars)
            {
                returnValue.Add(id, ValueById(id));
            }

            return returnValue;
        }

        /// <summary>
        /// 根据id组添加id-value对匹配的参数组
        /// </summary>
        /// <param name="vars"></param>
        public Dictionary<String, String> GetParamatersById(Encoding encoding, params String[] vars)
        {
            Dictionary<String, String> returnValue = new Dictionary<String, String>();
            foreach (String id in vars)
            {
                returnValue.Add(id, HttpUtility.UrlEncode(ValueById(id), encoding));
            }

            return returnValue;
        }

        /// <summary>
        /// 根据正则匹配返回html是否正确
        /// </summary>
        /// <param name="strRegex"></param>
        /// <returns></returns>
        public bool Success(String strRegex)
        {
            //匹配正则，匹配前将匹配组标记$符号暂时转换为临时字符串
            Regex regex = new Regex(strRegex, RegexOptions.IgnoreCase);
            Match mc = regex.Match(Html);

            return mc.Success;
        }

        /// <summary>
        /// 获取行
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="indexs">值所在的匹配组索引的集合</param>
        /// <returns></returns>
        public string[] GetRow(String strRegex, params int[] indexs)
        {
            string[] returnValue = new string[indexs.Length];

            for (int i = 0; i < indexs.Length; i++)
            {
                returnValue[i] = Match(strRegex, indexs[i]);
            }

            return returnValue;
        }

        /// <summary>
        /// 获取行集合
        /// </summary>
        /// <param name="strRegex">正则表达式</param>
        /// <param name="indexs">值所在的匹配组索引的集合</param>
        /// <returns></returns>
        public string[][] GetRows(String strRegex, params int[] indexs)
        {
            string[] rows = Values(strRegex);
            string[][] returnValue = new string[rows.Length][];

            for (int i = 0; i < rows.Length; i++)
            {
                HtmlContext ctxRow = new HtmlContext(rows[i]);
                returnValue[i] = ctxRow.GetRow(strRegex, indexs);
            }

            return returnValue;
        }
    }
}
